home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 22
/
Amiga Format AFCD22 (Jan 1998, Issue 106).iso
/
-in_the_mag-
/
converters
/
graphics
/
netpbm
/
pnmtopng
/
src
/
pngtopnm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-16
|
10KB
|
382 lines
/*
** pngtopnm.c - read a Portable Network Graphics file and produce a portable
** anymap
**
** Copyright (C) 1995 Alexander Lehmann
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
**
** modeled after giftopnm by David Koblas and
** with lots of bits pasted from pnglib.txt by Guy Eric Schalnat
*/
#include "pnm.h"
#include "png.h"
#define TRUE 1
#define FALSE 0
enum alpha_handling
{ none, alpha_only, mix };
/* prototypes */
static void store_pixel ARGS((xel *pix, png_uint_16 r, png_uint_16 g, png_uint_16 b, png_uint_16 a));
static png_uint_16 _get_png_val ARGS((png_byte **pp, int bit_depth));
static void print_text ARGS((png_info *info_ptr));
static void convertPNG ARGS((FILE *in));
static int verbose=FALSE;
static int text=FALSE;
static enum alpha_handling alpha=none;
static pixval maxval;
#define get_png_val(p) _get_png_val(&(p),info_ptr->bit_depth)
static
#ifdef __STDC__
png_uint_16 _get_png_val(png_byte **pp, int bit_depth)
#else
png_uint_16 _get_png_val(pp, bit_depth)
png_byte **pp;
int bit_depth;
#endif
{
png_uint_16 c=0;
if(bit_depth==16) {
c=(*((*pp)++))<<8;
}
c|=(*((*pp)++));
return c;
}
static
#ifdef __STD__
void store_pixel(xel *pix, png_uint_16 r, png_uint_16 g, png_uint_16 b, png_uint_16 a)
#else
void store_pixel(pix, r, g, b, a)
xel *pix;
png_uint_16 r, g, b, a;
#endif
{
if(alpha==alpha_only) {
PNM_ASSIGN1(*pix, a);
} else
if(alpha==mix) {
r*=(double)a/maxval;
g*=(double)a/maxval;
b*=(double)a/maxval;
PPM_ASSIGN(*pix, r, g, b);
} else {
PPM_ASSIGN(*pix, r, g, b);
}
}
static
#ifdef __STDC__
void print_text(png_info *info_ptr)
#else
void print_text(info_ptr)
png_info *info_ptr;
#endif
{
int i;
static char *month[]=
{"January", "Feburary", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"};
for(i=0;i<info_ptr->num_text;i++) {
pm_message("\n%s:%.*s", info_ptr->text[i].key,
(int)info_ptr->text[i].text_length,
info_ptr->text[i].text);
}
if(info_ptr->valid & PNG_INFO_tIME) {
pm_message("modification time: %02d %s %d %02d:%02d:%02d",
info_ptr->mod_time.day, month[info_ptr->mod_time.month],
info_ptr->mod_time.year, info_ptr->mod_time.hour,
info_ptr->mod_time.minute, info_ptr->mod_time.second);
}
}
static
#ifdef __STDC__
void convertPNG(FILE *in)
#else
void convertPNG(in)
FILE *in;
#endif
{
png_struct *png_ptr = malloc(sizeof (png_struct));
png_info *info_ptr = malloc(sizeof (png_info));
pixel *row;
png_byte **png_image;
png_byte *png_pixel;
pixel *pnm_pixel;
int x,y;
int linesize;
png_uint_16 c,c2,c3,a;
int pnm_type;
int i;
char *type_string;
char *alpha_string;
if(png_ptr==NULL || info_ptr==NULL)
pm_error("Cannot allocate PNGLIB structures");
if(setjmp(png_ptr->jmpbuf)==0) {
png_read_init(png_ptr);
png_info_init(info_ptr);
png_init_io(png_ptr, in);
png_read_info(png_ptr, info_ptr);
if(verbose) {
switch(info_ptr->color_type) {
case PNG_COLOR_TYPE_GRAY:
type_string="gray";
alpha_string="";
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type_string="gray";
alpha_string="+alpha";
break;
case PNG_COLOR_TYPE_PALETTE:
type_string="palette";
alpha_string="";
break;
case PNG_COLOR_TYPE_RGB:
type_string="truecolor";
alpha_string="";
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type_string="truecolor";
alpha_string="+alpha";
break;
}
if(info_ptr->valid & PNG_INFO_tRNS) {
alpha_string="+transparency";
}
pm_message("reading a %d x %d image, %d bit%s %s%s%s",
info_ptr->width, info_ptr->height,
info_ptr->bit_depth, info_ptr->bit_depth>1 ? "s" : "",
type_string, alpha_string,
info_ptr->interlace_type ? " Adam7 interlaced" : "");
}
png_image=malloc(info_ptr->height*sizeof(png_byte*));
if(png_image==NULL)
pm_error("couldn't alloc space for image");
if(info_ptr->bit_depth==16)
linesize=2*info_ptr->width;
else
linesize=info_ptr->width;
if(info_ptr->color_type==PNG_COLOR_TYPE_GRAY_ALPHA)
linesize*=2;
else
if(info_ptr->color_type==PNG_COLOR_TYPE_RGB)
linesize*=3;
else
if(info_ptr->color_type==PNG_COLOR_TYPE_RGB_ALPHA)
linesize*=4;
for(y=0;y<info_ptr->height;y++) {
png_image[y]=malloc(linesize);
if(png_image[y]==NULL)
pm_error("couldn't alloc space for image");
}
if (info_ptr->bit_depth < 8)
png_set_packing(png_ptr);
png_read_image(png_ptr, png_image);
png_read_end(png_ptr, info_ptr);
if(text) {
print_text(info_ptr);
}
if(info_ptr->valid & PNG_INFO_pHYs) {
float r;
r=(float) info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
if(r!=1.0) {
pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
r < 1.0 ? 'x' : 'y',
r < 1.0 ? 1.0 / r : r );
}
}
if ((row = pnm_allocrow(info_ptr->width)) == NULL)
pm_error("couldn't alloc space for image");
if(info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
maxval=255;
} else {
maxval=(1l<<info_ptr->bit_depth)-1;
}
if(alpha==alpha_only) {
if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
info_ptr->color_type == PNG_COLOR_TYPE_RGB) {
pnm_type=PBM_TYPE;
} else
if(info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
pnm_type=PBM_TYPE;
if(info_ptr->valid & PNG_INFO_tRNS) {
for(i=0;i<info_ptr->num_trans;i++) {
if(info_ptr->trans[i]!=0 && info_ptr->trans[i]!=maxval) {
pnm_type=PGM_TYPE;
break;
}
}
}
} else {
pnm_type=PGM_TYPE;
}
} else {
if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
if(info_ptr->bit_depth == 1) {
pnm_type=PBM_TYPE;
} else {
pnm_type=PGM_TYPE;
}
} else {
pnm_type=PPM_TYPE;
}
}
if (verbose)
pm_message("writing a %s file",
pnm_type == PBM_TYPE ? "PBM" :
pnm_type == PGM_TYPE ? "PGM" :
pnm_type == PPM_TYPE ? "PPM" :
"UNKNOWN!");
pnm_writepnminit(stdout, info_ptr->width, info_ptr->height, maxval,
pnm_type, FALSE);
for(y=0;y<info_ptr->height;y++) {
png_pixel=png_image[y];
pnm_pixel=row;
for(x=0;x<info_ptr->width;x++) {
c=get_png_val(png_pixel);
switch(info_ptr->color_type) {
case PNG_COLOR_TYPE_GRAY:
store_pixel(pnm_pixel, c, c, c,
(info_ptr->valid & PNG_INFO_tRNS) &&
c==info_ptr->trans_values.gray ?
0 : maxval);
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
a=get_png_val(png_pixel);
store_pixel(pnm_pixel, c, c, c, a);
break;
case PNG_COLOR_TYPE_PALETTE:
store_pixel(pnm_pixel, info_ptr->palette[c].red,
info_ptr->palette[c].green, info_ptr->palette[c].blue,
(info_ptr->valid & PNG_INFO_tRNS) &&
c<info_ptr->num_trans ?
info_ptr->trans[c] : maxval);
break;
case PNG_COLOR_TYPE_RGB:
c2=get_png_val(png_pixel);
c3=get_png_val(png_pixel);
store_pixel(pnm_pixel, c, c2, c3,
(info_ptr->valid & PNG_INFO_tRNS) &&
c ==info_ptr->trans_values.red &&
c2==info_ptr->trans_values.green &&
c3==info_ptr->trans_values.blue ?
0 : maxval);
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
c2=get_png_val(png_pixel);
c3=get_png_val(png_pixel);
a =get_png_val(png_pixel);
store_pixel(pnm_pixel, c, c2, c3, a);
break;
default:
pm_error("unknown PNG color type");
}
pnm_pixel++;
}
pnm_writepnmrow(stdout, row, info_ptr->width, maxval, pnm_type, FALSE);
}
png_read_destroy(png_ptr, info_ptr, (png_info *)NULL);
free(png_ptr);
free(info_ptr);
} else {
pm_error("setjmp returns error condition");
}
}
#ifdef __STDC__
int main(int argc, char *argv[])
#else
int main(argc, argv)
int argc;
char *argv[];
#endif
{
FILE *in;
int argn;
char *usage = "[-verbose] [-text] [-alpha|-mix] [pngfile]";
pnm_init(&argc, argv);
argn=1;
while(argn<argc && argv[argn][0]=='-' && argv[argn][1]!='\0') {
if(pm_keymatch(argv[argn], "-verbose", 2)) {
verbose=TRUE;
} else
if(pm_keymatch(argv[argn], "-text", 2)) {
text=TRUE;
} else
if(pm_keymatch(argv[argn], "-alpha", 2)) {
alpha=alpha_only;
} else
if(pm_keymatch(argv[argn], "-mix", 2)) {
alpha=mix;
} else {
pm_usage(usage);
}
argn++;
}
if(argn != argc) {
in = pm_openr(argv[argn]);
++argn;
} else {
in = stdin;
}
if(argn != argc)
pm_usage(usage);
convertPNG(in);
pm_close(in);
pm_close(stdout);
exit(0);
}